package ar.edu.itba.it.pdc.httpParser;

import java.util.LinkedList;
import java.util.List;

import ar.edu.itba.it.pdc.httpParser.interfaces.ImputCharGetter;
import ar.edu.itba.it.pdc.httpParser.models.Token;
import ar.edu.itba.it.pdc.httpParser.models.TokenType;
import ar.edu.itba.it.pdc.nio.Connection.ConectionType;

public class Lexer {

	private List<Token> tokensLeft =  new LinkedList<Token>();
	
	private List<Byte> actualToken = new LinkedList<Byte>();
	
	private ImputCharGetter icg;

	private boolean connectionClosed = false;
	
	ConectionType conectionType;

	public Lexer(ImputCharGetter icg, ConectionType conectionType) {
		this.icg = icg;
		this.conectionType = conectionType;
	}

	private void word(List<Token> tokens) {
		if (!actualToken.isEmpty()) {
			tokens.add(new Token(actualToken, TokenType.WORD));
			actualToken = new LinkedList<Byte>();
		}
	}

	private void other(List<Token> tokens, TokenType tokenType, Byte b) {
		actualToken.add(b);
		tokens.add(new Token(actualToken, tokenType));
		actualToken = new LinkedList<Byte>();

	}

	public List<Token> tokenise() {

		List<Token> tokens = tokensLeft;
		tokensLeft = new LinkedList<Token>();

		Byte b;
		Character c;
		while ((b = icg.read()) != null) {
			
			c = (char)(byte)b;
			if (c.equals('\r')) {
				word(tokens);
				actualToken.add(b);
			} else if (c.equals(' ') || c.equals('\t')) {
				word(tokens);
				other(tokens, TokenType.SPACE, b);

			} else if (c.equals('\n')) {
				if (!(actualToken.size() == 1 && ((Character)(char)actualToken.get(0).byteValue()).equals('\r'))) {
					word(tokens);
				}
				other(tokens, TokenType.CRLF, b);

			} else if (c.equals(':')) {
				word(tokens);
				other(tokens, TokenType.DOTS, b);

			} else if (c.equals('/')) {
				word(tokens);
				other(tokens, TokenType.DIVIDE, b);

			} else {
				actualToken.add(b);
			}
		}
		
		if (connectionClosed) {
			if (!actualToken.isEmpty()) {			
				tokens.add(new Token(actualToken, TokenType.WORD));
				actualToken  = new LinkedList<Byte>(); 
			} 
			tokens.add(new Token(null, TokenType.CONNECTIONCLOSED));
		}
		
		return tokens;

	}

	public void connectionClosed() {
		connectionClosed = true;
	}

	public Token getLastWord(int bytesToRead) {
		Token token = null;
		if(actualToken.size() == bytesToRead){
			token = new Token(actualToken, TokenType.WORD);
			actualToken = new LinkedList<Byte>();
		}else if(actualToken.size() > bytesToRead){
			token =new Token(actualToken.subList(0, bytesToRead), TokenType.WORD);
			actualToken = actualToken.subList(bytesToRead, actualToken.size());
		}
		return token;
	}

	public void returnTokens(List<Token> tokens) {
		tokensLeft = tokens;
	}
}
